//*****************************************************************************
//
// ADC.c
// 
// Brian Bonnet
// Steven Eckoff
//
// Initial Creation: February  2, 2011
// Last Modified:    February 11, 2011
// 
// This file provides driver functionality for the Stellaris LM3S8962 ADC.
// All of the Stellaris API call were provided by Texas Intruments.
//
// FOR LAB 01
//
// TA: Karthik Sankar
//
// Hardware Configuration: None
//
//*****************************************************************************
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
//#include "inc/hw_timer.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/interrupt.h"
#include "driverlib/timer.h"
#include "driverlib/adc.h"
#include "inc/lm3s8962.h"
#include "adccopy.h"
#include "os.h"

#define FALSE 0
#define TRUE 1

#define ADC_DEBUG 1
#if ADC_DEBUG
unsigned long intadccollect = 0;
unsigned long adccollect = 0;
unsigned long ADCDataLost = 0;
#endif
//***************************************************************  ******
//******************** GLOBALS ****************************  ************
//***************************************************************  ******
int(*CollectFunctionPt)();
volatile unsigned long sampleCount;
unsigned long Continuous = FALSE; // Indicates continuous sampling desired

void dummy(void){
 for(;;){}
}

// ***** IntADCCollet *****
//
// The interrupt handler for period ADC samples. Set
// up by calling ADC_Collect(). Stores ADC value on
// the buffer that define in the ADC_Collect() call
//
// inputs: none
// outputs: none
//
void IntADCCollect ( void ) {
  unsigned short data;
  
  #if ADC_DEBUG
  intadccollect++;
  //GPIO_PORTC_DATA_R ^= 0x80;
  #endif

      // Clear the ADC interrupt
  ADCIntClear(ADC0_BASE, 1);
      // Retrieve data from sample sequence 1 FIFO
      // ADC Sample Sequence 1 FIFO register
  data = ADC_SSFIFO1_R;
  #if ADC_DEBUG 
  ADCDataLost += CollectFunctionPt(data);
  #else
  CollectFunctionPt(data);
  #endif
  
  if(Continuous == FALSE ) {
    sampleCount--;
	if(sampleCount==0){  // Check if the desired number of samples has been reached
      TimerDisable(TIMER1_BASE,TIMER_A); // Disable timer 1A
	}
  }
}


// ******** ADC_Open *********
//
// Initializes the ADC hardware
// 
// input: none
// output: none
//
void ADC_Open( void ) {
      // Enable the clock to the ADC module
  SYSCTL_RCGC0_R |= SYSCTL_RCGC0_ADC;
      // Configure the ADC to sample at 500K
  SYSCTL_RCGC0_R |= SYSCTL_RCGC0_ADCSPD500K;
      // Disable sample sequences 1 
  ADCSequenceDisable(ADC_BASE, 1);
      // Configure sample sequence 1: timer trigger, priority = 0
  ADCSequenceConfigure(ADC_BASE, 1, ADC_TRIGGER_TIMER, 0);
      //  Set SS1 interrupt priority
  IntPrioritySet(INT_ADC0SS1,0);
      // Enable the interrupt for sample sequence 1
  ADCIntEnable(ADC_BASE, 1);
      // Enable SS1 Interupt in NVIC
  IntEnable(INT_ADC0SS1);
}

// ***** ADC_Collect *****
//
// This function enables periodic ADC sampling for a
// specified number of samples at a given rate. Each 
// sample is stored the specified buffer
//
// inputs: channelNum      - ADC channel to sample from
//         fs              - frequency of sample rate
//         buffer          - buffer array to store values
//         numberOfSampels - the number of samples to take
// outputs: none
//
void ADC_Collect( unsigned int channelNum, unsigned int fs,
					int functionPt(), unsigned long numberOfSamples ) {
					
      // Pass parameters to globals to communicate with handler
  CollectFunctionPt = functionPt;
  if(numberOfSamples == 0) {
    Continuous = TRUE; // Indicates to handler that continuous sampling is desired
	sampleCount = 0;
  }
  else {
    Continuous = FALSE;
    sampleCount = numberOfSamples;
  }
      //  Disable Timer1
  TimerDisable(TIMER1_BASE,TIMER_A);
        //  Load the period for timer1
  TimerLoadSet(TIMER1_BASE, TIMER_A, RUN_SPEED/fs);
      // Disable sample sequences 1 
  ADCSequenceDisable(ADC_BASE, 1);
      // Configure sample sequence 1: timer trigger, priority = 0
  ADCSequenceConfigure(ADC_BASE, 1, ADC_TRIGGER_TIMER, 0);
      //  Configure Sample sequence
  switch(channelNum){
    case 0:
      ADCSequenceStepConfigure(ADC_BASE, 1, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END );
	  break;
	case 1:
      ADCSequenceStepConfigure(ADC_BASE, 1, 0, ADC_CTL_CH1 | ADC_CTL_IE | ADC_CTL_END );
	  break;
	case 2:
      ADCSequenceStepConfigure(ADC_BASE, 1, 0, ADC_CTL_CH2 | ADC_CTL_IE | ADC_CTL_END );
	  break;
	case 3:
      ADCSequenceStepConfigure(ADC_BASE, 1, 0, ADC_CTL_CH3 | ADC_CTL_IE | ADC_CTL_END );
	  break;
	default:
	  break;
  }
      // Enable the interrupt for sample sequence 1
  ADCIntEnable(ADC_BASE, 1);
      // Enable sample sequences 1 
  ADCSequenceEnable(ADC_BASE, 1);
      // Enable SS1 Interupt in NVIC
  IntEnable(INT_ADC0SS1);
      //  Enable Timer1A
  TimerEnable(TIMER1_BASE,TIMER_A);
}

// ***** ADC_In *****
// 
// Returns a single ADC sample from the specified
// channel
//
// input:  channelNum - ADC channel to sample from
// output: (long) ADC sample
//
unsigned long ADC_In(unsigned int channelNum) {
	volatile unsigned long sample;
  //
  // Disable sample sequences 0 before making any configuration changes
  //
  // ADC Active Sample Sequencer register
  //
  ADCSequenceDisable(ADC0_BASE, 0);
  
  /*ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);

  ADCSequenceStepConfigure(ADC0_BASE, 0, channelNum, ADC_CTL_TS | ADC_CTL_IE |
                             ADC_CTL_END);

  ADCIntClear(ADC0_BASE, 0);

  ADCSequenceEnable(ADC0_BASE, 0);

  ADCProcessorTrigger(ADC0_BASE, 0);

  while(!ADCIntStatus(ADC0_BASE, 0, false))
        {
        }

  ADCSequenceDataGet(ADC0_BASE, 0, sample);

  return *sample;*/
  //
  // Sample Sequence priority 0,1,2,3 by default
  //
  // Set up sequence triggers: sequence 0 = processor
  //
  // ADC Event Multiplexer Select register
  //
  ADC_EMUX_R |= ADC_EMUX_EM0_PROCESSOR;

  //
  // Configure sample sequence 0 input multiplexer:
  //
  // - Step 0: Select Analog Input
  //
  // ADC Sample Sequence Input Multiplexer Select 0 register
  //
  // This is ignored when the temp sensor is enabled
  /*switch (channelNum) {
  case 3 : ADC_SSMUX0_R = ( 3 << ADC_SSMUX0_MUX0_S ); break;
  case 2 : ADC_SSMUX0_R = ( 2 << ADC_SSMUX0_MUX0_S ); break;
  case 1 : ADC_SSMUX0_R = ( 1 << ADC_SSMUX0_MUX0_S ); break;
  default	 : ADC_SSMUX0_R = ( 0 << ADC_SSMUX0_MUX0_S );
  }*/	

  //										   
  // Configure sample sequence 0 control 
  //
  // - Step 0: temp
  //
  // ADC Sample Sequence Control 0 register
  //
  ADC_SSCTL0_R = (ADC_SSCTL0_END0 | ADC_SSCTL0_TS0);



  //
  // Enable sample sequences 0
  //
  // ADC Active Sample Sequencer register
  //
  ADC_ACTSS_R |= (ADC_ACTSS_ASEN0);

  //
  // Software Trigger ADC sample sequence 0
  //					
  ADC_PSSI_R = ADC_PSSI_SS0;

  //
  //	Blind wait while fifo is empty
  //
  while ((ADC_SSFSTAT0_R & ADC_SSFSTAT0_EMPTY)){}

  //
  //	Read data from ss0 fifo
  //
  sample = ADC_SSFIFO0_R; // return sample 0
  return sample;
}


